package com.wl.dzt.sys.core.dao;

import com.wl.dzt.sys.core.dao.curd.TransactionHandler;
import com.wl.dzt.sys.core.dao.curd.sql.SqlSearchResult;
import com.wl.dzt.sys.core.dao.curd.validate.Validate;
import com.wl.dzt.sys.core.dao.select.Select;
import com.wl.dzt.sys.core.dao.select.term.Term;
import com.wl.dzt.sys.util.FieldUtil;
import com.wl.dzt.sys.util.LogicUtil;
import com.wl.dzt.sys.util.clazz.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;
import org.springframework.transaction.UnexpectedRollbackException;

import java.util.List;
import java.util.Map;

/**
 * @author wl_code@163.com
 * @date 2018/7/5/005
 * @version 1.0
 * @description 数据库控制类
 * 提供静态方法用于控制数据库的相关操作
 * 
 */
@Component
public class DB {

	/**
	 * 日志
	 */
	private static Logger logger = LoggerFactory.getLogger(DB.class);

	/**
	 * DAO
	 */
	public static JDao J_DAO;

	/**
	 * <b>删除</b>
	 * <p>
	 * 删除一个实体
	 * </p>
	 *
	 * @param clazz
	 * @param id
	 * @param validates
	 * @return
	 */
	public static boolean delete(Class<?> clazz, String id, Validate... validates) {
		return J_DAO.delete(clazz, id, validates);
	}

	/**
	 * <b>批量删除</b>
	 * <p>
	 * 根据编号集合批量删除一些实体
	 * </p>
	 *
	 * @param clazz
	 * @param ids
	 * @param validates
	 * @return
	 */
	public static boolean delete(Class<?> clazz, String[] ids, Validate... validates) {
		return startTx(() -> {
			for (String id : ids) {
				if (!J_DAO.delete(clazz, id, validates))
					return false;
			}
			return true;
		});
	}

	/**
	 * <b>保存</b>
	 * <p>
	 * 根据实体保存数据
	 * </p>
	 *
	 * @param entity
	 * @param validates
	 * @return
	 */
	public static boolean save(Object entity, Validate... validates) {
		return J_DAO.save(entity, validates);
	}

	/**
	 * <b>批量保存</b>
	 * <p>
	 * 根据一组实体保存数据
	 * </p>
	 *
	 * @param entitys
	 * @param validates
	 * @return
	 */
	public static boolean saves(Object[] entitys, Validate... validates) {
		return startTx(() -> {
			for (Object entity : entitys) {
				if (!save(entity, validates)) {
					return false;
				}
			}
			return true;
		});
	}

	/**
	 * <b>保存并返回详情</b>
	 * <p>
	 * 根据验证条件保存数据<br>
	 * 验证失败的时候返回错误信息
	 * </p>
	 *
	 * @param entity
	 * @param validates
	 * @return
	 */
	public static List<Validate> saveByDetailed(Object entity, Validate... validates) {
		return J_DAO.saveByDetailed(entity, validates);
	}

	/**
	 * <b>删除并且返回详情 </b>
	 * <p>
	 * 根据验证条件删除数据<br>
	 * 删除失败的时候返回错误信息
	 * </p>
	 *
	 * @param clazz
	 * @param id
	 * @param validates
	 * @return
	 */
	public static List<Validate> deleteByDetailed(Class<?> clazz, String id, Validate... validates) {
		return J_DAO.deleteByDetailed(clazz, id, validates);
	}

	/**
	 * <b>查询数据</b>
	 * <p>
	 * 根据条件查询集合数据
	 * </p>
	 *
	 * @param select
	 * @return
	 */
	public static <T> List<T> list(Select select) {
		return J_DAO.list(select);
	}

	/**
	 * <b>不适配查询 </b>
	 * <p>
	 * 根据查询条件查询数据<br>
	 * 不会自动装箱成实体,以便提高性能
	 * </p>
	 *
	 * @param select
	 * @return
	 */
	public static List<Map<String, Object>> listByMap(Select select) {
		return J_DAO.listByMap(select);
	}

	/**
	 * <b>根据id获取某个实体</b>
	 * <p>
	 * 多级时候需要指定父级字段
	 * </p>
	 *
	 * @param clazz
	 * @param id
	 * @param fields
	 * @return
	 */
	public static <T> T get(Class<?> clazz, String id, String... fields) {
		return J_DAO.get(clazz, id, fields);
	}

	/**
	 * <b>根据条件查找某个实体</b>
	 * <p>
	 * 多级时候需要指定父级字段
	 * </p>
	 *
	 * @param clazz
	 * @param terms
	 * @param fields
	 * @return
	 */
	public static <T> T get(Class<?> clazz, Term[] terms, String... fields) {
		return J_DAO.get(clazz, terms, fields);
	}

	/**
	 * <b>查看总数</b>
	 * <p>
	 * 根据查询条件查询某个表的总数
	 * </p>
	 *
	 * @param select
	 * @return
	 */
	public static Integer count(Select select) {
		return J_DAO.count(select);
	}

	/**
	 * <b>开始事务</b>
	 * <p>
	 * 开始一组事务,返回fase即回滚
	 * </p>
	 *
	 * @param transaactionHandler
	 * @return
	 */
	public static boolean startTx(TransactionHandler transaactionHandler) {
		try {
			return J_DAO.startTx(transaactionHandler);
		} catch (UnexpectedRollbackException e) {
			e.printStackTrace();
			logger.error("事务执行失败,数据存在异常!");
			return false;
		}
	}

	/**
	 * <b> 执行一段sql</b>
	 * <p>
	 * 根据sql语句已经参数执行一段sql<br>
	 * </p>
	 *
	 * @param sql
	 * @param args
	 * @return
	 */
	public static List<Map<String, Object>> executeSql(String sql, Object... args) {
		return J_DAO.executeSql(sql, args);
	}

	/**
	 * <b> 是否存在ID</b>
	 * <p>
	 * 判断某个实体是否存在id这个属性
	 * </p>
	 *
	 * @param entity
	 * @return
	 */
	public static Boolean exitId(Object entity) {
		return !LogicUtil.isNull(FieldUtil.doGetMethod(entity, "id"));
	}

	/**
	 * <b>设置id</b>
	 * <p>
	 * 设置某个实体的id属性
	 * </p>
	 *
	 * @param entity
	 * @param id
	 */
	public static void setId(Object entity, String id) {
		BeanMap beanMap = BeanMap.create(entity);
		beanMap.put("id", id);
	}

	/**
	 * <b>根据id查询实体</b>
	 * <p>
	 * 返回map
	 * </p>
	 *
	 * @param clazz
	 * @param id
	 * @param fields
	 * @return
	 */
	public static Map<String, Object> getByMap(Class<?> clazz, String id, String... fields) {
		return J_DAO.getByMap(clazz, id, fields);
	}

	/**
	 * <b>获取id</b>
	 * <p>
	 * 得到某个实体的id属性
	 * </p>
	 *
	 * @param entity
	 * @return
	 */
	public static String getId(Object entity) {
		BeanMap beanMap = BeanMap.create(entity);
		return LogicUtil.thenNull(beanMap.get("id"), null);
	}

	/**
	 * <b>存在id 但是其他字段没值 </b>
	 * <p>
	 * 判断某个实体是否存在id,并且其他字段没有值
	 * </p>
	 *
	 * @param entity
	 * @return
	 */
	public static boolean idOtherFields(Object entity) {
		BeanMap beanMap = BeanMap.create(entity);
		int count = beanMap.size();
		for (Object key : beanMap.keySet()) {
			if (beanMap.get(key) == null)
				count--;
		}
		count -= ClassUtil.transientCountByObject(entity);
		return (count == 1 && DB.exitId(entity));
	}

	/**
	 * 
	 * <b>是否是个空实体</b>
	 * <p>
	 * 根据所传递的实体对象，如果其中任何字段都没有值则为空实体
	 * </p>
	 *
	 * @param entity
	 * @return
	 */
	public static boolean isEmptyEntity(Object entity) {
		BeanMap beanMap = BeanMap.create(entity);
		int count = beanMap.size();
		for (Object key : beanMap.keySet()) {
			if (beanMap.get(key) == null)
				count--;
		}
		count -= ClassUtil.transientCount(entity.getClass());
		return count == 0;
	}

	/**
	 * <b>sql表达式查询</b>
	 * <p>
	 * 通过 sql配合条件占位符进行一次sql查询
	 * </p>
	 *
	 * @param select
	 * @return
	 */
	public static SqlSearchResult selectBySqlExp(Select select) {
		return J_DAO.selectBySqlExp(select);
	}
}
